//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<enumeration10.h>
///	@path	~/src/graphics/dx9/
///	@date	2007/09/26
///	@desc	Enumerates available Direct3D9 adapters, devices, modes, etc.

#pragma once

#include "xeres.h"

// DirectX 9 header
#define D3D_DISABLE_9EX 1
#include <d3d9.h>
#include <d3dx9.h>

// STL
#include <vector>

#include "lib/utilities/callback.h"

namespace xeres {

	// forward declarations
	class EnumDeviceSettings9;

	/*!
		\class	EnumDeviceInfo9
		\brief
	*/
	class EnumDeviceInfo9
	{
	public:
		/// \dtor
		~EnumDeviceInfo9( void );

	//@ data
		UINT		m_adapterOrdinal;
		D3DDEVTYPE	m_deviceType;
		D3DCAPS9	m_caps;
		std::vector<EnumDeviceSettings9*> m_deviceSettingsList; 
	};

	/*!
		\class	EnumAdapterInfo9
		\brief	A class describing an adapter which contains
				a unique adapter ordinal that is installed on the system.
	*/
	class EnumAdapterInfo9
	{
	public:
		/// \dtor
		~EnumAdapterInfo9( void );

	//@ data
		UINT					m_adapterOrdinal;
		D3DADAPTER_IDENTIFIER9	m_adapterIdentifier;
		WCHAR					m_uniqueDescription[256];

		std::vector<D3DDISPLAYMODE> m_displayModeList;
		std::vector<EnumDeviceInfo9*> m_deviceInfoList;
	};

	struct EnumDSMSConflict9
	{
		D3DFORMAT				dsFormat;
		D3DMULTISAMPLE_TYPE		msType;
	};

	/*!
		\class	EnumDeviceSettings9
		\brief
	*/
	class EnumDeviceSettings9
	{
	public:

		UINT				m_adapterOrdinal;
		D3DDEVTYPE			m_deviceType;
		D3DFORMAT			m_adapterFormat;
		D3DFORMAT			m_backbufferFormat;
		BOOL				m_windowed;

		std::vector<D3DFORMAT>				m_depthStencilFormatList;
		std::vector<D3DMULTISAMPLE_TYPE>	m_multiSampleTypeList;
		std::vector<DWORD>					m_multiSampleQualityList;
		std::vector<UINT>					m_presentIntervalList;
		std::vector<EnumDSMSConflict9>		m_dsmsConflictList;

		EnumAdapterInfo9 *	m_adapterInfo;
		EnumDeviceInfo9 *	m_deviceInfo;
	};

	/*!
		\class	EnumD3D9
		\brief	Enumerates available Direct3D10 adapters, devices, modes, etc.
	*/
	class EnumD3D9
	{
	public:

		/// \instance
		static EnumD3D9& instance( void );

		// initialize
		void Initialize( bool bEnumerateAllAdapterFormats );

		// finalize
		void Finalize( void );

		void SetRequirePostPixelShaderBlending( bool bRequire ) { m_requirePostPixelShaderBlending = bRequire; }
		void SetResolutionMinMax( UINT nMinWidth, UINT nMinHeight, UINT nMaxWidth, UINT nMaxHeight );
		void SetRefreshMinMax( UINT nMin, UINT nMax );
		void SetMultisampleQualityMax( UINT nMax );
		void GetPossibleVertexProcessingList( bool* pbSoftwareVP, bool* pbHardwareVP, bool* pbPureHarewareVP, bool* pbMixedVP );
		void SetPossibleVertexProcessingList( bool bSoftwareVP, bool bHardwareVP, bool bPureHarewareVP, bool bMixedVP );
		const std::vector<D3DFORMAT>& GetPossibleDepthStencilFormatList( void );
		const std::vector<D3DMULTISAMPLE_TYPE>& GetPossibleMultisampleTypeList( void );
		const std::vector<UINT>& GetPossiblePresentIntervalList( void );
		void ResetPossibleDepthStencilFormats( void );
		void ResetPossibleMultisampleTypeList( void );
		void ResetPossiblePresentIntervalList( void );

		// These should be called after Enumerate() is called
		const std::vector<EnumAdapterInfo9*>& GetAdapterInfoList( void );
		EnumAdapterInfo9 * GetAdapterInfo( UINT AdapterOrdinal );
		EnumDeviceInfo9 * GetDeviceInfo( UINT AdapterOrdinal, D3DDEVTYPE DeviceType );
		EnumDeviceSettings9* GetDeviceSettingsCombo( UINT AdapterOrdinal, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, BOOL Windowed );

	private:

		/// \ctor
		EnumD3D9( void );

		/// \dtor
		~EnumD3D9( void );

		void Enumerate( void );
		HRESULT EnumerateDevices( EnumAdapterInfo9* pAdapterInfo, std::vector<D3DFORMAT>* pAdapterFormatList );
		HRESULT EnumerateDeviceSettings( EnumAdapterInfo9* pAdapterInfo, EnumDeviceInfo9* pDeviceInfo, std::vector<D3DFORMAT>* pAdapterFormatList );
		void BuildDepthStencilFormatList( EnumDeviceSettings9* pDeviceCombo );
		void BuildMultiSampleTypeList( EnumDeviceSettings9* pDeviceCombo );
		void BuildDSMSConflictList( EnumDeviceSettings9* pDeviceCombo );
		void BuildPresentIntervalList( EnumDeviceInfo9* pDeviceInfo, EnumDeviceSettings9* pDeviceCombo );
		void ClearAdapterInfoList( void );

	//@ data

		bool m_inited;
		bool m_enumerateAllAdapterFormats;
		bool m_requirePostPixelShaderBlending;
		bool m_spare0;

		bool m_softwareVP;
		bool m_hardwareVP;
		bool m_pureHarewareVP;
		bool m_mixedVP;

		UINT m_minWidth;
		UINT m_maxWidth;
		UINT m_minHeight;
		UINT m_maxHeight;
		UINT m_refreshMin;
		UINT m_refreshMax;
		UINT m_multisampleQualityMax;

		std::vector<D3DFORMAT> m_depthStencilPossibleList;
		std::vector<EnumAdapterInfo9 *> m_adapterInfoList;

		std::vector<D3DMULTISAMPLE_TYPE> m_multiSampleTypeList;
		std::vector<UINT> m_presentIntervalList;

		function<void(D3DCAPS9*,D3DFORMAT,D3DFORMAT,bool)> m_deviceAcceptable;
	};

} // namespace xeres
